package ddz.logic.game;

import ch.qos.logback.classic.Logger;
import com.kaka.notice.annotation.Handler;
import ddz.constants.Crypto;
import ddz.constants.ErrCode;
import ddz.constants.ErrLevel;
import ddz.constants.OpCode;
import ddz.core.Table;
import ddz.core.TableState;
import ddz.core.Player;
import ddz.core.TrusteeType;
import ddz.db.dao.TableDao;
import ddz.db.dao.UserDao;
import ddz.db.entity.UserInfo;
import ddz.db.service.CensusService;
import ddz.db.service.MatcherService;
import ddz.net.LogicDataHandler;
import ddz.net.ProtocolMessage;
import ddz.protos.GameExit;
import ddz.utils.Toolkit;
import org.slf4j.LoggerFactory;

import java.util.Map;

/**
 * 退出房间、下桌
 *
 * @author zkpursuit
 */
@Handler(cmd = OpCode.cmd_exit_room, type = String.class)
public class ExitTableHandler extends LogicDataHandler {

    private static final Logger logger = (Logger) LoggerFactory.getLogger(ExitTableHandler.class);

    @Override
    protected void execute(ProtocolMessage msg) throws Exception {
        if (msg.getBody() instanceof Map) {
            this.execute((Map<String, Object>) msg.getBody());
            return;
        }
//        if (bytes != null && bytes.length > 0) {
//            GameExit.CsExit csExit = GameExit.CsExit.parseFrom(bytes);
//            int mode = csExit.getMode();
//            int place = csExit.getPlace();
//            ConfPlaceInfoManager placeInfoManager = this.retrieveProxy(ConfPlaceInfoManager.class);
//            if (GameMode.isExists(mode) && placeInfoManager.isExist(place)) {
//                MatcherService matcherService = this.retrieveProxy(MatcherService.class);
//                matcherService.exitMatch(mode, place, getUid());
//            }
//        }
        CensusService censusService = this.retrieveProxy(CensusService.class);
        MatcherService matcherService = this.retrieveProxy(MatcherService.class);
        //如果玩家正在被匹配，退出房间就须退出匹配
        matcherService.exitMatch(msg.uid(), matcher -> {
            String matcherId = matcher.getId();
            String[] parts = matcherId.split(":");
            int _mode = Integer.parseInt(parts[0]);
            int _place = Integer.parseInt(parts[1]);
            censusService.reduce(_mode, _place, msg.uid());
        });
        UserDao userDao = this.retrieveProxy(UserDao.class);
        UserInfo userInfo = userDao.getUserInfo(msg.uid());
        if (userInfo == null) {
            logger.info("玩家 [{}] 数据不存在", msg.uid());
            sendError(msg.ctx(), opcode(), ErrLevel.ERROR, ErrCode.data_err);
            return;
        }
        long deskId = userInfo.getDeskId();

        GameExit.ScExit.Builder scExitBuilder = GameExit.ScExit.newBuilder();
        scExitBuilder.setResult(true);
        if (deskId <= 0) {
            //logger.error("玩家（" + msg.uid() + "）未加入任何房间");
            scExitBuilder.setSeat(-1).setUid(msg.uid());
            this.sendData(msg.uid(), Crypto.isCrypto, opcode(), scExitBuilder.build().toByteArray());
            return;
        }
        TableDao tableDao = this.retrieveProxy(TableDao.class);
        Table table = tableDao.getDesk(deskId);
        if (table == null) {
            //logger.error("玩家（" + msg.uid() + "）未加入任何房间");
            scExitBuilder.setSeat(-1).setUid(msg.uid());
            this.sendData(msg.uid(), Crypto.isCrypto, opcode(), scExitBuilder.build().toByteArray());
            //sendError(ctx(), opcode(), ErrLevel.ERROR, ErrCode.no_join_room);
            return;
        }
        if (table.getState() == TableState.scrap) {
            //房间已解散
            logger.error("玩家 [{}] 所退出的房间 [{}] 已解散", msg.uid(), table.getId());
            //sendError(ctx(), opcode(), ErrLevel.INFO, ErrCode.no_join_room);
            userInfo.setDeskId(0);
            userDao.insertOrUpdateUser(userInfo);
            censusService.reduce(table.getMode(), table.getPlace(), msg.uid());
            scExitBuilder.setSeat(-1).setUid(msg.uid());
            this.sendData(msg.uid(), Crypto.isCrypto, opcode(), scExitBuilder.build().toByteArray());
            return;
        }
        Player player = table.getPlayerByUid(msg.uid());
        if (player == null) {
            logger.error("玩家 [{}：{}] 在 [{}] 房间中无对应的数据", player.getSeatIndex(), msg.uid(), table.getId());
            sendError(msg.ctx(), opcode(), ErrLevel.ERROR, ErrCode.data_err);
            return;
        }
        Player[] players = table.getPlayers();
        TableState state = table.getState();
        if (state != TableState.jiesuan && state != TableState.none && state != TableState.scrap) {
            //游戏中强制退出由服务器托管代打
            player.setTimeoutCount(TrusteeType.exit.getTimeoutCount());
        } else {
            table.setState(TableState.scrap);
            player.setReady(false);
            for (Player member : players) {
                if (!member.getUid().equals(userInfo.getUid())) {
                    UserInfo uinfo = userDao.getUserInfo(member.getUid());
                    if (uinfo != null && uinfo.getDeskId() == deskId) {
                        uinfo.setDeskId(0);
                        userDao.insertOrUpdateUser(uinfo);
                    }
                }
            }
        }
        tableDao.insertOrUpdateDesk(table);
        scExitBuilder.setSeat(player.getSeatIndex())
                .setUid(msg.uid())
                .setDeskId(deskId);
        byte[] respBytes = scExitBuilder.build().toByteArray();
        for (Player member : players) {
            this.sendData(member.getUid(), Crypto.isCrypto, opcode(), respBytes);
        }
    }

    /**
     * 处理结算时托管用户自动退出，此事件由内部调度处理
     *
     * @param paramMap 事件参数
     */
    private void execute(Map<String, Object> paramMap) {
        UserInfo userInfo = (UserInfo) paramMap.get("userInfo");
        Table table = (Table) paramMap.get("desk");

        final long uid = userInfo.getUid();

        if (uid > Toolkit.maxInteger()) {
            CensusService censusService = this.retrieveProxy(CensusService.class);
            MatcherService matcherService = this.retrieveProxy(MatcherService.class);
            //如果玩家正在被匹配，退出房间就须退出匹配
            matcherService.exitMatch(uid, matcher -> {
                String matcherId = matcher.getId();
                String[] parts = matcherId.split(":");
                int _mode = Integer.parseInt(parts[0]);
                int _place = Integer.parseInt(parts[1]);
                censusService.reduce(_mode, _place, uid);
            });
            censusService.reduce(table.getMode(), table.getPlace(), uid);
        }

        Player player = table.getPlayerByUid(uid);
        player.setReady(false);
        userInfo.setDeskId(0);
        table.setState(TableState.scrap);

        GameExit.ScExit.Builder scExitBuilder = GameExit.ScExit.newBuilder();
        scExitBuilder.setResult(true);
        scExitBuilder.setSeat(player.getSeatIndex())
                .setUid(userInfo.getUid())
                .setDeskId(table.getId());
        byte[] respBytes = scExitBuilder.build().toByteArray();
        Player[] players = table.getPlayers();
        for (Player member : players) {
            this.sendData(member.getUid(), Crypto.isCrypto, opcode(), respBytes);
        }
        paramMap.clear();
    }
}
